package com.xianggu.designMode.combination.demo04;

import com.xianggu.designMode.combination.demo04.impl.DivideExpression;
import com.xianggu.designMode.combination.demo04.impl.MultipExpression;
import com.xianggu.designMode.combination.demo04.impl.NumberExpression;
import com.xianggu.designMode.combination.demo04.impl.SubtractExpression;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

/**
 * @author chengjy
 * @date 2025/3/20
 */
public class ExpressionParser {

    private final String infixExpression;
    Set<String> operator = Set.of("+", "-", "*", "/");
    private int index = 0;
    public ExpressionParser(String infixExpression) {
        this.infixExpression = infixExpression;
    }
    // 将中缀表达式转为后缀表达式
    public List<String > toSuffix(){
        List<String > suffixStack = new ArrayList<>();
        LinkedList<String > stack = new LinkedList<>();

        while (index < infixExpression.length()){
            String c = String.valueOf(infixExpression.charAt(index++));
            // 处理括号的情况 （）
            if( c.equals("(")) { // 如果是左括号，则直接入辅助栈
                stack.addLast(c);
            }else if (c.equals(")" )){// 如果是右括号需要将辅助栈顶所有元素弹出，直到遇到左括号为止
                while (!stack.getLast().equals("(")) {
                    String lastStr = stack.removeLast();
                    suffixStack.add(lastStr);
                }
                stack.removeLast(); // 弹出左括号
            }else if (c.equals("+") || c.equals("-")){// 加减的操作符优先级一样一块处理
                while (isOperator(stack)){
                    suffixStack.add(stack.removeLast());
                }
                stack.addLast(c);
            }else if (c.equals("*") || c.equals("/")){
                while (stack.getLast().equals("*") || stack.getLast().equals("/")){// 优先让辅助栈顶的操作符进入结果栈
                    suffixStack.add(stack.removeLast());
                }
                stack.addLast(c);
            } else if (isDigit(c)){// 如果是数字，则直接加入后缀表达式\
                boolean whileFlag = false;
                // 有可能是连续的数子，这里需要判断
                while (index <= infixExpression.length()-1 && isDigit(String.valueOf(infixExpression.charAt(index)))){
                    c += infixExpression.charAt(index++);
                    whileFlag = true;
                }
                if (whileFlag) {
                    index--;
                }
                suffixStack.add(c);
            }else if (c.equals(" ")){// 如果是空格则跳过
            }else{
                throw new RuntimeException("非法字符");
            }
        }
        if(!stack.isEmpty()){
            while (!stack.isEmpty()){
                suffixStack.add(stack.removeLast());
            }
        }
        return suffixStack;
    }

    public Expression parse(){
        List<String> suffix = toSuffix();
        LinkedList<Expression> stack = new LinkedList<>();// 计算栈

        for (String s : suffix) {
            // 如果是数字，则直接入栈
            if (isDigit(s)){
                stack.addLast(new NumberExpression(Integer.parseInt(s)));
            }else if(operator.contains(s)){
                Expression right = stack.removeLast();
                Expression left = stack.removeLast();
                switch (s){
                    case "+":
                        stack.addLast(new AddExpression(left, right));
                        break;
                    case "-":
                        stack.addLast(new SubtractExpression(left, right));
                        break;
                    case "*":
                        stack.addLast(new MultipExpression(left, right));
                        break;
                    case "/":
                        stack.addLast(new DivideExpression(left, right));
                }
            }
        }
        return stack.getLast();
    }

    private boolean isDigit(String c){
        return c.matches("\\d");
    }
    private boolean isOperator(LinkedList<String > stack){
        if (stack.isEmpty()){
            return false;
        }
        return operator.contains(stack.getLast());
    }
}
